home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / net_src.arc / telnet.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-05-08  |  9.6 KB  |  488 lines

  1. #include <stdio.h>
  2. #include "config.h"
  3. #include "global.h"
  4. #include "mbuf.h"
  5. #include "timer.h"
  6. #include "icmp.h"
  7. #include "netuser.h"
  8. #include "tcp.h"
  9. #include "telnet.h"
  10. #include "session.h"
  11. #include "ftp.h"
  12. #include "iface.h"
  13. #include "ax25.h"
  14. #include "lapb.h"
  15. #include "finger.h"
  16. #include "nr4.h"
  17.  
  18. #define    CTLZ    26
  19.  
  20. extern char nospace[];
  21. extern char badhost[];
  22. int refuse_echo = 0;
  23. int unix_line_mode = 0;    /* if true turn <cr> to <nl> when in line mode */
  24.  
  25. #ifdef    DEBUG
  26. char *t_options[] = {
  27.     "Transmit Binary",
  28.     "Echo",
  29.     "",
  30.     "Suppress Go Ahead",
  31.     "",
  32.     "Status",
  33.     "Timing Mark"
  34. };
  35. #endif
  36.  
  37. /* Execute user telnet command */
  38. int
  39. dotelnet(argc,argv)
  40. int argc;
  41. char *argv[];
  42. {
  43.     void t_state(),rcv_char(),tn_tx();
  44.     char *inet_ntoa();
  45.     int32 resolve();
  46.     int send_tel();
  47.         int unix_send_tel();
  48.     struct session *s;
  49.     struct telnet *tn;
  50.     struct tcb *tcb;
  51.     struct socket lsocket,fsocket;
  52.  
  53.  
  54.     lsocket.address = ip_addr;
  55.     lsocket.port = lport++;
  56.     if((fsocket.address = resolve(argv[1])) == 0){
  57.         printf(badhost,argv[1]);
  58.         return 1;
  59.     }
  60.     if(argc < 3)
  61.         fsocket.port = TELNET_PORT;
  62.     else
  63.         fsocket.port = atoi(argv[2]);
  64.  
  65.     /* Allocate a session descriptor */
  66.     if((s = newsession()) == NULLSESSION){
  67.         printf("Too many sessions\n");
  68.         return 1;
  69.     }
  70.     if((s->name = malloc((unsigned)strlen(argv[1])+1)) != NULLCHAR)
  71.         strcpy(s->name,argv[1]);
  72.     s->type = TELNET;
  73.     if ((refuse_echo == 0) && (unix_line_mode != 0)) {
  74.         s->parse = unix_send_tel;
  75.     } else {
  76.         s->parse = send_tel;
  77.     }
  78.     current = s;
  79.  
  80.     /* Create and initialize a Telnet protocol descriptor */
  81.     if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN){
  82.         printf(nospace);
  83.         s->type = FREE;
  84.         return 1;
  85.     }
  86.     tn->session = s;    /* Upward pointer */
  87.     tn->state = TS_DATA;
  88.     s->cb.telnet = tn;    /* Downward pointer */
  89.  
  90.     tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,0,
  91.      rcv_char,tn_tx,t_state,0,(char *)tn);
  92.  
  93.     tn->tcb = tcb;    /* Downward pointer */
  94.     go();
  95.     return 0;
  96. }
  97.  
  98. /* Process typed characters */
  99. int
  100. unix_send_tel(buf,n)
  101. char *buf;
  102. int16 n;
  103. {
  104.     int i;
  105.  
  106.     for (i=0; (i<n) && (buf[i] != '\r'); i++)
  107.         ;
  108.     if (buf[i] == '\r') {
  109.         buf[i] = '\n';
  110.         n = i+1;
  111.     }
  112.     send_tel(buf,n);
  113. }
  114. int
  115. send_tel(buf,n)
  116. char *buf;
  117. int16 n;
  118. {
  119.     struct mbuf *bp,*qdata();
  120.     if(current == NULLSESSION || current->cb.telnet == NULLTN
  121.      || current->cb.telnet->tcb == NULLTCB)
  122.         return;
  123.     /* If we're doing our own echoing and recording is enabled, record it */
  124.     if(!current->cb.telnet->remote[TN_ECHO] && current->record != NULLFILE)
  125.         fwrite(buf,1,n,current->record);
  126.     bp = qdata(buf,n);
  127.     send_tcp(current->cb.telnet->tcb,bp);
  128. }
  129.  
  130. /* Process incoming TELNET characters */
  131. int
  132. tel_input(tn,bp)
  133. register struct telnet *tn;
  134. struct mbuf *bp;
  135. {
  136.     char c;
  137.     void doopt(),dontopt(),willopt(),wontopt(),answer();
  138.     FILE *record;
  139.     char *memchr();
  140.  
  141.     /* Optimization for very common special case -- no special chars */
  142.     if(tn->state == TS_DATA){
  143.         while(bp != NULLBUF && memchr(bp->data,IAC,bp->cnt) == NULLCHAR){
  144.             if((record = tn->session->record) != NULLFILE)
  145.                 fwrite(bp->data,1,bp->cnt,record);
  146.             while(bp->cnt-- != 0)
  147.                 putchar(*bp->data++);
  148.             bp = free_mbuf(bp);
  149.         }
  150.     }
  151.     while(pullup(&bp,&c,1) == 1){
  152.         switch(tn->state){
  153.         case TS_DATA:
  154.             if(uchar(c) == IAC){
  155.                 tn->state = TS_IAC;
  156.             } else {
  157.                 if(!tn->remote[TN_TRANSMIT_BINARY])
  158.                     c &= 0x7f;
  159.                 putchar(c);
  160.                 if((record = tn->session->record) != NULLFILE)
  161.                     putc(c,record);
  162.             }
  163.             break;
  164.         case TS_IAC:
  165.             switch(uchar(c)){
  166.             case WILL:
  167.                 tn->state = TS_WILL;
  168.                 break;
  169.             case WONT:
  170.                 tn->state = TS_WONT;
  171.                 break;
  172.             case DO:
  173.                 tn->state = TS_DO;
  174.                 break;
  175.             case DONT:
  176.                 tn->state = TS_DONT;
  177.                 break;
  178.             case IAC:
  179.                 putchar(c);
  180.                 tn->state = TS_DATA;
  181.                 break;
  182.             default:
  183.                 tn->state = TS_DATA;
  184.                 break;
  185.             }
  186.             break;
  187.         case TS_WILL:
  188.             willopt(tn,c);
  189.             tn->state = TS_DATA;
  190.             break;
  191.         case TS_WONT:
  192.             wontopt(tn,c);
  193.             tn->state = TS_DATA;
  194.             break;
  195.         case TS_DO:
  196.             doopt(tn,c);
  197.             tn->state = TS_DATA;
  198.             break;
  199.         case TS_DONT:
  200.             dontopt(tn,c);
  201.             tn->state = TS_DATA;
  202.             break;
  203.         }
  204.     }
  205. }
  206.  
  207. /* Telnet receiver upcall routine */
  208. void
  209. rcv_char(tcb,cnt)
  210. register struct tcb *tcb;
  211. int16 cnt;
  212. {
  213.     struct mbuf *bp;
  214.     struct telnet *tn;
  215.     FILE *record;
  216. #ifdef    FLOW
  217.     extern int ttyflow;
  218. #endif
  219.     if((tn = (struct telnet *)tcb->user) == NULLTN){
  220.         /* Unknown connection; ignore it */
  221.         return;
  222.     }
  223.     /* Hold output if we're not the current session */
  224.     if(mode != CONV_MODE || current == NULLSESSION
  225. #ifdef    FLOW
  226.      || !ttyflow    /* Or if blocked by keyboard input -- hyc */
  227. #endif
  228.      || current->type != TELNET || current->cb.telnet != tn)
  229.         return;
  230.  
  231.     if(recv_tcp(tcb,&bp,cnt) > 0)
  232.         tel_input(tn,bp);
  233.  
  234.     fflush(stdout);
  235.     if((record = tn->session->record) != NULLFILE)
  236.         fflush(record);
  237. }
  238. /* Handle transmit upcalls. Used only for file uploading */
  239. void
  240. tn_tx(tcb,cnt)
  241. struct tcb *tcb;
  242. int16 cnt;
  243. {
  244.     struct telnet *tn;
  245.     struct session *s;
  246.     struct mbuf *bp;
  247.     int size;
  248.  
  249.     if((tn = (struct telnet *)tcb->user) == NULLTN
  250.      || (s = tn->session) == NULLSESSION
  251.      || s->upload == NULLFILE)
  252.         return;
  253.     if((bp = alloc_mbuf(cnt)) == NULLBUF)
  254.         return;
  255.     if((size = fread(bp->data,1,cnt,s->upload)) > 0){
  256.         bp->cnt = (int16)size;
  257.         send_tcp(tcb,bp);
  258.     } else {
  259.         free_p(bp);
  260.     }
  261.     if(size != cnt){
  262.         /* Error or end-of-file */
  263.         fclose(s->upload);
  264.         s->upload = NULLFILE;
  265.         free(s->ufile);
  266.         s->ufile = NULLCHAR;
  267.     }
  268. }
  269.  
  270. /* State change upcall routine */
  271. void
  272. t_state(tcb,old,new)
  273. register struct tcb *tcb;
  274. char old,new;
  275. {
  276.     struct telnet *tn;
  277.     char notify = 0;
  278.     extern char *tcpstates[];
  279.     extern char *reasons[];
  280.     extern char *unreach[];
  281.     extern char *exceed[];
  282.  
  283.     /* Can't add a check for unknown connection here, it would loop
  284.      * on a close upcall! We're just careful later on.
  285.      */
  286.     tn = (struct telnet *)tcb->user;
  287.  
  288.     if(current != NULLSESSION && current->type == TELNET && current->cb.telnet == tn)
  289.     {
  290.         notify = 1;
  291.         cooked();    /* prettify things... -- hyc */
  292.     }
  293.  
  294.     switch(new){
  295.     case CLOSE_WAIT:
  296.         if(notify)
  297.             printf("%s\n",tcpstates[new]);
  298.         close_tcp(tcb);
  299.         break;
  300.     case CLOSED:    /* court adjourned */
  301.         if(notify){
  302.             printf("%s (%s",tcpstates[new],reasons[tcb->reason]);
  303.             if(tcb->reason == NETWORK){
  304.                 switch(tcb->type){
  305.                 case DEST_UNREACH:
  306.                     printf(": %s unreachable",unreach[tcb->code]);
  307.                     break;
  308.                 case TIME_EXCEED:
  309.                     printf(": %s time exceeded",exceed[tcb->code]);
  310.                     break;
  311.                 }
  312.             }
  313.             printf(")\n");
  314.             cmdmode();
  315.         }
  316.         del_tcp(tcb);
  317.         if(tn != NULLTN)
  318.             free_telnet(tn);
  319.         break;
  320.     default:
  321.         if(notify)
  322.             printf("%s\n",tcpstates[new]);
  323.         break;
  324.     }
  325.     fflush(stdout);
  326. }
  327. /* Delete telnet structure */
  328. static
  329. free_telnet(tn)
  330. struct telnet *tn;
  331. {
  332.     if(tn->session != NULLSESSION)
  333.         freesession(tn->session);
  334.  
  335.     if(tn != NULLTN)
  336.         free((char *)tn);
  337. }
  338.  
  339. /* The guts of the actual Telnet protocol: negotiating options */
  340. void
  341. willopt(tn,opt)
  342. struct telnet *tn;
  343. char opt;
  344. {
  345.     int ack;
  346.     void answer();
  347.  
  348. #ifdef    DEBUG
  349.     printf("recv: will ");
  350.     if(uchar(opt) <= NOPTIONS)
  351.         printf("%s\n",t_options[opt]);
  352.     else
  353.         printf("%u\n",opt);
  354. #endif
  355.     
  356.     switch(uchar(opt)){
  357.     case TN_TRANSMIT_BINARY:
  358.     case TN_ECHO:
  359.     case TN_SUPPRESS_GA:
  360.         if(tn->remote[uchar(opt)] == 1)
  361.             return;        /* Already set, ignore to prevent loop */
  362.         if(uchar(opt) == TN_ECHO){
  363.             if(refuse_echo){
  364.                 /* User doesn't want to accept */
  365.                 ack = DONT;
  366.                 break;
  367.             } else
  368.                 raw();        /* Put tty into raw mode */
  369.         }
  370.         tn->remote[uchar(opt)] = 1;
  371.         ack = DO;            
  372.         break;
  373.     default:
  374.         ack = DONT;    /* We don't know what he's offering; refuse */
  375.     }
  376.     answer(tn,ack,opt);
  377. }
  378. void
  379. wontopt(tn,opt)
  380. struct telnet *tn;
  381. char opt;
  382. {
  383.     void answer();
  384.  
  385. #ifdef    DEBUG
  386.     printf("recv: wont ");
  387.     if(uchar(opt) <= NOPTIONS)
  388.         printf("%s\n",t_options[uchar(opt)]);
  389.     else
  390.         printf("%u\n",uchar(opt));
  391. #endif
  392.     if(uchar(opt) <= NOPTIONS){
  393.         if(tn->remote[uchar(opt)] == 0)
  394.             return;        /* Already clear, ignore to prevent loop */
  395.         tn->remote[uchar(opt)] = 0;
  396.         if(uchar(opt) == TN_ECHO)
  397.             cooked();    /* Put tty into cooked mode */
  398.     }
  399.     answer(tn,DONT,opt);    /* Must always accept */
  400. }
  401. void
  402. doopt(tn,opt)
  403. struct telnet *tn;
  404. char opt;
  405. {
  406.     void answer();
  407.     int ack;
  408.  
  409. #ifdef    DEBUG
  410.     printf("recv: do ");
  411.     if(uchar(opt) <= NOPTIONS)
  412.         printf("%s\n",t_options[uchar(opt)]);
  413.     else
  414.         printf("%u\n",uchar(opt));
  415. #endif
  416.     switch(uchar(opt)){
  417. #ifdef    FUTURE    /* Use when local options are implemented */
  418.         if(tn->local[uchar(opt)] == 1)
  419.             return;        /* Already set, ignore to prevent loop */
  420.         tn->local[uchar(opt)] = 1;
  421.         ack = WILL;
  422.         break;
  423. #endif
  424.     default:
  425.         ack = WONT;    /* Don't know what it is */
  426.     }
  427.     answer(tn,ack,opt);
  428. }
  429. void
  430. dontopt(tn,opt)
  431. struct telnet *tn;
  432. char opt;
  433. {
  434.     void answer();
  435.  
  436. #ifdef    DEBUG
  437.     printf("recv: dont ");
  438.     if(uchar(opt) <= NOPTIONS)
  439.         printf("%s\n",t_options[uchar(opt)]);
  440.     else
  441.         printf("%u\n",uchar(opt));
  442. #endif
  443.     if(uchar(opt) <= NOPTIONS){
  444.         if(tn->local[uchar(opt)] == 0){
  445.             /* Already clear, ignore to prevent loop */
  446.             return;
  447.         }
  448.         tn->local[uchar(opt)] = 0;
  449.     }
  450.     answer(tn,WONT,opt);
  451. }
  452. static
  453. void
  454. answer(tn,r1,r2)
  455. struct telnet *tn;
  456. int r1,r2;
  457. {
  458.     struct mbuf *bp,*qdata();
  459.     char s[3];
  460.  
  461. #ifdef    DEBUG
  462.     switch(r1){
  463.     case WILL:
  464.         printf("sent: will ");
  465.         break;
  466.     case WONT:
  467.         printf("sent: wont ");
  468.         break;
  469.     case DO:
  470.         printf("sent: do ");
  471.         break;
  472.     case DONT:
  473.         printf("sent: dont ");
  474.         break;
  475.     }
  476.     if(r2 <= 6)
  477.         printf("%s\n",t_options[r2]);
  478.     else
  479.         printf("%u\n",r2);
  480. #endif
  481.  
  482.     s[0] = IAC;
  483.     s[1] = r1;
  484.     s[2] = r2;
  485.     bp = qdata(s,(int16)3);
  486.     send_tcp(tn->tcb,bp);
  487. }
  488.